package com.market.member.service.impl;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.block.channel.enums.ReportTypeEnum;
import com.block.channel.service.IChannelCountInfoService;
import com.block.channel.service.IChannelFlowReportInfoService;
import com.block.common.bean.CommonParam;
import com.block.common.bean.SessionBean;
import com.block.common.constant.AppRspCodeConstant;
import com.block.common.model.dto.LoginReqDTO;
import com.block.common.service.LogFactory;
import com.block.common.vo.ResponseVo;
import com.block.db.entity.MemberBaseInfo;
import com.block.db.entity.MemberSourceInfo;
import com.block.db.entity.MerchantBaseInfo;
import com.block.db.mapper.MemberBaseInfoMapper;
import com.block.db.mapper.MemberSourceInfoMapper;
import com.block.db.mapper.MerchantBaseInfoMapper;
import com.block.match.model.vo.MatchOrderItem;
import com.block.match.model.vo.MatchResultVO;
import com.block.match.service.IDataMatchOrderInfoService;
import com.block.match.service.IMatchHandleService;
import com.market.member.enums.UserTypeEnum;
import com.market.member.factory.LoginTypeFactory;
import com.market.member.model.dto.LoginResultDTO;
import com.market.member.model.vo.UserInfoVO;
import com.market.member.service.IMemberBaseInfoService;
import com.market.member.service.IMemberLoginSessionService;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 
 * @since 2023-08-05
 */
@Service
public class MemberBaseInfoServiceImpl extends ServiceImpl<MemberBaseInfoMapper, MemberBaseInfo> implements IMemberBaseInfoService {

    private static final Logger log = LogFactory.getCommLog();

    @Autowired
    IMemberLoginSessionService memberLoginSessionService;
    @Autowired
    IChannelCountInfoService channelCountInfoService;
    @Autowired
    IChannelFlowReportInfoService channelFlowReportInfoService;
    @Autowired
    IMatchHandleService matchHandleService;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    MerchantBaseInfoMapper merchantBaseInfoMapper;
    @Autowired
    MemberSourceInfoMapper memberSourceInfoMapper;
    @Autowired
    IDataMatchOrderInfoService iDataMatchOrderInfoService;

    private static final long EXPIRE_TIME = 12;

    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    public ResponseVo toLogin(LoginReqDTO loginReqDTO, CommonParam commonParam){

        ResponseVo responseVo = LoginTypeFactory.getService(loginReqDTO.getLoginType()).toLogin(loginReqDTO);
        if (!AppRspCodeConstant.SUCCESS.equals(responseVo.getRspCode())){
            log.info("【用户登录】登录失败【result】{}", JSON.toJSONString(responseVo));
            return responseVo;
        }

        LoginResultDTO loginResultDTO = responseVo.getData().toJavaObject(LoginResultDTO.class);
        loginResultDTO.setLoginType(loginReqDTO.getLoginType());

        /**
         * 记录登陆token信息
         */
        SessionBean sessionBean = memberLoginSessionService.loginSession(loginResultDTO, commonParam);
        if (sessionBean == null){
            return new ResponseVo(AppRspCodeConstant.LOGIN_ERROR, "登录失败，请重试");
        }

        MemberBaseInfo memberBaseInfo = loginResultDTO.getMemberBaseInfo();
        /**
         * 获取用户 授权金额等信息
         */

        /**
         * 登陆注册完成之后，进行的操作
         * todo
         */
        // 随机用户不进行后续操作
        if (!ObjectUtil.equals(memberBaseInfo.getType(), UserTypeEnum.RANDOM.getValue())){
            this.afterLoginHandle(loginResultDTO, commonParam);
        }
        UserInfoVO userInfoVO = new UserInfoVO();
        userInfoVO.setToken(sessionBean.getToken());
        userInfoVO.setUid(String.valueOf(sessionBean.getUid()));
        userInfoVO.setUsername(sessionBean.getUsername());
        userInfoVO.setLimitAmount(memberBaseInfo.getCreditLimitAmount());

        userInfoVO.setChannelCode(sessionBean.getChannelCode());
        userInfoVO.setChannelName(sessionBean.getChannelName());
        userInfoVO.setRegChannelCode(sessionBean.getRegChannelCode());
        userInfoVO.setRegChannelName(sessionBean.getRegChannelName());

        userInfoVO.setAuthFlag(memberBaseInfo.getAuthFlag());
        userInfoVO.setFaceFlag(memberBaseInfo.getFaceFlag());
        userInfoVO.setSourceFlag(memberBaseInfo.getSourceFlag());

        return new ResponseVo(AppRspCodeConstant.SUCCESS, userInfoVO);
    }

    private void afterLoginHandle(LoginResultDTO loginResultDTO, CommonParam commonParam){

        channelCountInfoService.countLoginRegDataInfo(commonParam.getChannelCode(), loginResultDTO.isNewMember(), commonParam);

        // 2023/9/1 渠道信息上报
        // 只有新用户的才上报
        if (loginResultDTO.isNewMember()){
            channelFlowReportInfoService.handleFlowReport(commonParam, loginResultDTO.getUid(), ReportTypeEnum.REGISTER);
        }
    }

    /**
     * 登陆之后获取用户信息
     * @param sessionBean
     * @param commonParam
     * @return
     */
    @Override
    public ResponseVo getUserInfo(SessionBean sessionBean, CommonParam commonParam) {

        MemberBaseInfo memberBaseInfo = this.getById(sessionBean.getUid());
        /**
         * 用户基本信息
         */
        UserInfoVO userInfoVO = new UserInfoVO();
        userInfoVO.setToken(sessionBean.getToken());
        userInfoVO.setUid(String.valueOf(sessionBean.getUid()));
        userInfoVO.setUsername(memberBaseInfo.getUsername());
        userInfoVO.setMobile(DesensitizedUtil.mobilePhone(memberBaseInfo.getMobile()));
        userInfoVO.setLimitAmount(memberBaseInfo.getCreditLimitAmount());

        userInfoVO.setChannelCode(sessionBean.getChannelCode());
        userInfoVO.setChannelName(sessionBean.getChannelName());
        userInfoVO.setRegChannelCode(sessionBean.getRegChannelCode());
        userInfoVO.setRegChannelName(sessionBean.getRegChannelName());

        userInfoVO.setAuthFlag(memberBaseInfo.getAuthFlag());
        userInfoVO.setFaceFlag(memberBaseInfo.getFaceFlag());
        userInfoVO.setSourceFlag(memberBaseInfo.getSourceFlag());

        return new ResponseVo(AppRspCodeConstant.SUCCESS, userInfoVO);
    }

    @Override
    public ResponseVo pushMembers() {

        // 查询所有启用状态的机构信息
        QueryWrapper<MerchantBaseInfo> merchantQueryWrapper = new QueryWrapper<>();
        merchantQueryWrapper.eq("status", "1");
//        List<MerchantBaseInfo> merchantBaseInfos = merchantBaseInfoMapper.selectList(merchantQueryWrapper);

        List<MerchantBaseInfo> merchantBaseInfos = merchantBaseInfoMapper.selectOpenMerchantAndPrice();

        String REDIS_KEY = "pushUid:" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));

        Boolean hasKey = redisTemplate.hasKey(REDIS_KEY);
        if (!hasKey) {
            initData(REDIS_KEY);
        }

        int successCount = 0;
        JSONObject jsonObject = new JSONObject();
        List<Object> uidsObj = redisTemplate.opsForSet().pop(REDIS_KEY, 10);
        if (uidsObj != null && !uidsObj.isEmpty()) {
            for (Object obj : uidsObj) {
                if (!(obj instanceof Number)) {
                    continue;
                }
                Long uid = ((Number) obj).longValue();
                // 判断是否为占位元素，若是则跳过
                if (Objects.equals(0L, uid)) {
                    // 需要重新添加占位值
                    redisTemplate.opsForSet().add(REDIS_KEY, 0L);
                    continue;
                }
                // 推送该用户
                MemberSourceInfo memberSourceInfo = memberSourceInfoMapper.getEntityByUidLock(uid);
                //选择机构推送type
                String type = "1";
                List<MatchResultVO> matchResult0 = matchHandleService.getMatchResult0(memberSourceInfo,type);
                //不为空走推送逻辑
                if(matchResult0 != null && !matchResult0.isEmpty()){
                    for (MatchResultVO matchResultVO : matchResult0) {
                        String orderId = extractOrderId(matchResultVO);
                        String orderItemIds = extractOrderItemIds(matchResultVO);

                        ResponseVo responseVo = iDataMatchOrderInfoService.approveToPush(uid, orderId, orderItemIds, "");

                        String rspCode = responseVo.getRspCode();

                        if (AppRspCodeConstant.SUCCESS.equals(rspCode)) {
                            successCount++;
                        }
                    }

                }
//                for (MerchantBaseInfo merchantBaseInfo : merchantBaseInfos) {
//                    Integer infoId = merchantBaseInfo.getId();
//
//                    ResponseVo<?> responseVo = matchHandleService.handlePushManual(infoId.toString(), String.valueOf(uid));
//
//                }
                // 每个用户推送完成之后，在进行休眠
                // 单个用户推送不休眠
                ThreadUtil.safeSleep(2000);
            }
        }
        String notificationMessage = "推送完成，推送成功数量：" + successCount;
        log.info("-------夜间推送数据完毕{}",notificationMessage);
        jsonObject.put("notificationMessage", notificationMessage);
        return new ResponseVo(AppRspCodeConstant.SUCCESS,jsonObject);
    }

    public void initData(String redisKey){
        QueryWrapper<MemberSourceInfo> queryWrapper = new QueryWrapper<>();
        LocalDate today = LocalDate.now();
        LocalDate yesterday = today.minusDays(1);
        LocalDateTime startTime = yesterday.atTime(18, 0, 0);
        LocalDateTime endTime = today.atTime(9, 0, 0);

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String startStr = startTime.format(formatter);
        String endStr = endTime.format(formatter);

        queryWrapper.between("create_time", startStr, endStr)
                .notIn("channel_code", Arrays.asList("6H1SGE","WEM537","2ZQ0PH","LD03FN"))
                .between("age", 22, 55);
//                    .last("limit 8");
        List<MemberSourceInfo> memberSourceInfos = memberSourceInfoMapper.selectList(queryWrapper);

        int memberSize = memberSourceInfos.size();

        String message = startStr +endStr + "认证资质数：" + memberSize;
        log.info("-----开始推送数据:{}", message);
        for (MemberSourceInfo sourceInfo : memberSourceInfos) {
            Long uid = sourceInfo.getUid();
            redisTemplate.opsForSet().add(redisKey, uid);
        }

        // 添加占位值
        redisTemplate.opsForSet().add(redisKey, 0L);
        redisTemplate.expire(redisKey, EXPIRE_TIME, TimeUnit.HOURS);
    }

    private String extractOrderId(MatchResultVO result) {
        if (result == null || StrUtil.isBlank(result.getOrderId())) {
            return "";
        }
        return result.getOrderId();
    }
    private String extractOrderItemIds(MatchResultVO result) {
        if (result == null || result.getOrderItemList() == null || result.getOrderItemList().isEmpty()) {
            return "[]";
        }
        List<String> orderItemIds = result.getOrderItemList().stream()
                .filter(Objects::nonNull)
                .map(MatchOrderItem::getOrderItemId)
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.toList());

        return JSON.toJSONString(orderItemIds);
    }

}
